#ifndef UNPACK_HPP
#define UNPACK_HPP 1

#include "head.hpp"
#include "decode.hpp"
#include "bitinput.hpp"
#include "window.hpp"
#include "filter.hpp"
#include "vm.hpp"
#include "fwrite.hpp"

namespace fur
{
   const int LOW_DIST_REP_COUNT=16;
   
   class Unpack
   {
   public:
      Unpack(std::ifstream &infile, std::ofstream &outfile, const FileHead &filehead) throw(Exception);
      ~Unpack() throw();
      void do_unpack();
   protected:
      void insert_old_dist(size_t distance) throw();
      void insert_last_match(size_t distance, size_t size) throw();
      bool read_table();
      bool read_end_of_block();
      bool read_vm();
      bool add_vm(uint16_t first, uint8_t *vmcode, uint16_t size);
      void write_to_file();
      void write_area(uint32_t start, uint32_t end);
      void execute_code(VMPreparedProgram *prg);
      void initfilters();
      void unpack_29();
      uint32_t window_avail_size();
   private:
      vector<Filter*> filters;
      vector<Filter*> prgstack;
      vector<int> oldfilterlengths;
      int lastfilter;
      BitInput bitinput;
      Window window;
      FWrite fw;
      Decode litdecode;
      Decode distdecode;
      Decode lowdistdecode;
      Decode repdecode;
      Decode bitdecode;
      uint32_t filecrc;
      uint8_t version;
      uint32_t lowdistrepcount;
      uint32_t prevlowdist;
      size_t lastdist;
      size_t lastsize;
      size_t olddist[4];
      uint8_t oldtable[HTS];
      VisualMachine vm;
      size_t writtenposi;
   };
} // end of namespace fur
#endif /* unpack.hpp */
